package android.FiltrosJava;

import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;

public class MotionBlur extends AbstractImageBasic{
	private float angle = 0.0f;	
	private float distance = 1.0f;
	private float zoom = 0.0f;	
    
	public MotionBlur( float distance, float angle, float zoom ) {
		setMotionBlur(distance, angle, zoom );
    }
	
	public void setMotionBlur(float distance, float angle, float zoom ){
		this.distance = distance;
        this.angle = angle;
        this.zoom = zoom;
	}

	public BufferedImage applyFilter(BufferedImage src) {
        int dimX = src.getWidth();
        int dimY = src.getHeight();
                
        BufferedImage dst = copiaImagem(src);
        WritableRaster rasterSrc = src.getRaster();
        WritableRaster rasterDst = dst.getRaster();
        int numBands = rasterSrc.getNumBands();
    	int[] imageDataSrc = new int[numBands];    	    	   					
    	
		int cx = dimX/2;
		int cy = dimY/2;		
				
        float imageRadius = (float)Math.sqrt( cx*cx + cy*cy );
        float translateX = (float)(distance * Math.cos( angle ));
        float translateY = (float)(distance * -Math.sin( angle ));
        float maxDistance = distance + zoom*imageRadius;
		int repetitions = (int)maxDistance;
		AffineTransform t = new AffineTransform();
		Point2D.Float p = new Point2D.Float();		
        int[][] coord = new int[repetitions][2];
        				
		for (int y = 0; y < Math.ceil(dimY/2.0f); y++) {
			for (int x = 0; x < Math.ceil(dimX/2.0f); x++) {				
				int count = 0;
				for (int i = 0; i < repetitions; i++) {
					int newX = x, newY = y;
					float f = (float)i/repetitions;

					p.x = x;
					p.y = y;
					t.setToIdentity();
					t.translate( cx+f*translateX, cy+f*translateY );
					float s = 1-zoom*f;
					t.scale( s, s );
					
					t.translate( -cx, -cy );
					t.transform( p, p );
					newX = (int)p.x;
					newY = (int)p.y;

					if (newX < 0 || newX >= dimX) {
						newX = (int) negativeMod( newX, dimX );						
					}
					if (newY < 0 || newY >= dimY) {
						newY = (int) negativeMod( newY, dimY );						
					}
					
					count++;
					
					coord[i][0] = newY - y;
					coord[i][1] = newX - x;					
				}
				imageDataSrc = computeCor(rasterDst,numBands,x,y,1,1,count,coord);
				rasterSrc.setPixel(x,y,imageDataSrc);
				
				imageDataSrc = computeCor(rasterDst,numBands,dimX - x - 1,y,-1,1,count,coord);
				rasterSrc.setPixel(dimX - x - 1,y,imageDataSrc);
				
				imageDataSrc = computeCor(rasterDst,numBands,x,dimY - y - 1,1,-1,count,coord);
				rasterSrc.setPixel(x,dimY - y - 1,imageDataSrc);
				
				imageDataSrc = computeCor(rasterDst,numBands,dimX - x - 1,dimY - y - 1,-1,-1,count,coord);
				rasterSrc.setPixel(dimX - x - 1,dimY - y - 1,imageDataSrc);
			}
		}
		dst = null;
		coord = null;
		imageDataSrc = null;
        return src;
    }
    
    private int[] computeCor(WritableRaster raster, int numBands, int x, int y, int mx, int my, int count, int[][] coord){    	    	
    	int px, py;
    	int[] cor = new int[numBands];
    	    	    	
    	if (count == 0)
    		raster.getPixel(x,y,cor);
    	else{    		
    		for (int k = 0; k < numBands; k++)
				cor[k] = 0;
    		    		
    		for (int c = 0; c < count; c++){
    			py = (int)(y + my * coord[c][0]);
    			px = (int)(x + mx * coord[c][1]);
    			for (int k = 0; k < numBands; k++)
					cor[k] += raster.getSample(px, py, k);
    		}
    		for (int k = 0; k < numBands; k++)
				cor[k] = delimitaCor((int)(cor[k]/count)); 
    	}    	   	
    	
    	return cor;
    }    
}